﻿using System;
using System.Reflection;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Text;
using Microsoft.VisualStudio.TestTools.UnitTesting;
using System.Configuration;
using System.Collections.Specialized;

namespace YaTools.Yaml.UnitTests
{
    [TestClass]
    public class TraceTests
    {
        static TraceSource myTraceSource = new TraceSource("myTraceSource",SourceLevels.Warning);

        private static IEnumerable<Switch> GetSwitches()
        {
            var switches = (typeof(Switch).GetField(
                    "switches",BindingFlags.NonPublic | BindingFlags.Static))
                    .GetValue(null) as List<WeakReference>;

            return switches
                .Select(w => w.Target as Switch)
                .OrderBy(w=>w.DisplayName);
        }

        private void ShowEnvironment()
        {
            Trace.WriteLine("System.Environment:");
            Trace.Indent();
            try {
                Trace.WriteLine( Environment.CommandLine, "CommandLine");
                Trace.WriteLine( Environment.CurrentDirectory, "CurrentDirectory");
                Trace.WriteLine( Environment.MachineName, "MachineName");
                Trace.WriteLine( Environment.OSVersion, "OSVersion" );
                Trace.WriteLine( Environment.Version, "Version"); 
                Trace.WriteLine( "GetEnvironmentVariables():");
                Trace.Indent();
                try {
                    var v = Environment.GetEnvironmentVariables();
                    foreach( var e in v.Keys)
                        Trace.WriteLine( v[e], e.ToString());
                } finally { Trace.Unindent(); }
            } finally { Trace.Unindent(); }
        }

        [TestMethod]
        public void ShowConfiguration1x()
        {
            var settings = System.Configuration.ConfigurationManager.AppSettings;
            var keys = settings.AllKeys;
            if (keys.Count() > 0)
            {
                Trace.WriteLine("System.Configuration.ConfigurationManager.AppSettings: ");
                Trace.Indent();
                try
                {
                    foreach (string key in keys)
                    {
                        Trace.WriteLine(settings[key], key);
                    }
                }
                finally { Trace.Unindent(); }
            }
        }

        [TestMethod]
        public void ShowConfiguration2x()
        {
            var c = ConfigurationManager.OpenExeConfiguration(ConfigurationUserLevel.None);
            if (c!= null)
            {
                Trace.WriteLine("System.Configuration.Configuration:");
                Trace.Indent();
                try 
                {
                    Trace.WriteLine( c.HasFile, "HasFile");
                    Trace.WriteLine( c.FilePath, "FilePath");
                    TraceSectionGroup(c.RootSectionGroup);
                } finally { Trace.Unindent(); }
            }
            //public AppSettingsSection AppSettings { get; }
            //public ConnectionStringsSection ConnectionStrings { get; }
            //public ContextInformation EvaluationContext { get; }
            //public string FilePath { get; }
            //public bool HasFile { get; }
            //public ConfigurationLocationCollection Locations { get; }
            //public bool NamespaceDeclared { get; set; }
            //public ConfigurationSectionGroup RootSectionGroup { get; }
            //public ConfigurationSectionGroupCollection SectionGroups { get; }
            //public ConfigurationSectionCollection Sections { get; }
            //public ConfigurationSection GetSection(string sectionName);
            //public ConfigurationSectionGroup GetSectionGroup(string sectionGroupName);
        }

        private void TraceKey(string key, Action action )
        {
            Trace.WriteLine("", key );
            Trace.Indent();
            try { action(); } finally { Trace.Unindent(); }
        }
        
        private void TraceSection(ConfigurationSection s)
        {
            TraceKeys("Properties", s.ElementInformation.Properties, key => {
                Trace.WriteLine("", key);
                    
            });
        }

        private void TraceSectionGroup(ConfigurationSectionGroup g)
        {
            TraceKeys( "Sections", g.Sections, key => TraceKey(key, () => TraceSection(g.Sections[key])));
            TraceKeys("SectionGroups", g.SectionGroups, key => TraceKey(key, () => TraceSectionGroup(g.SectionGroups[key])));
        }

        private static void TraceCollection<T>( string name, IEnumerable<T> sequence, Action<T> action )
        {
            if (sequence != null)
            {
                Trace.WriteLine(String.Format("{0}:"));
                Trace.Indent();
                try
                {
                    foreach (T t in sequence)
                        action(t);
                }
                finally
                {
                    Trace.Unindent();
                }
            }
        }

        private static void TraceDictionary<TKEY, TVALUE>(string name, IDictionary<TKEY, TVALUE> d, Action<TKEY, TVALUE> action)
        {
            if (d != null )
            {
                Trace.WriteLine(String.Format("{0}:", name));
                Trace.Indent();
                var e = d.GetEnumerator();
                try
                {
                    while (e.MoveNext())
                        action(e.Current.Key, e.Current.Value);
                }
                finally
                {
                    Trace.Unindent();
                }
            }
        }

        private static IEnumerable<string> Keys(NameObjectCollectionBase d)
        {
            List<string> keys = new List<string>();
            foreach (string key in d.Keys) keys.Add(key);
            return keys.OrderBy(k => k);
        }

        private static void TraceKeys(string name, NameObjectCollectionBase d, Action<string> action)
        {
            if (d != null && d.Count > 0 )
            {
                Trace.WriteLine(String.Format("{0}:", name));
                Trace.Indent();
                var e = d.GetEnumerator();
                try
                {
                    foreach (string key in Keys(d))
                    {
                        action( key);
                    }
                }
                finally
                {
                    Trace.Unindent();
                }
            }
        }

        [TestMethod]
        public void ListSwitches()
        {
            myTraceSource.TraceEvent(TraceEventType.Warning, 12);
            ShowEnvironment();
            ShowConfiguration1x();
            Trace.WriteLine("System.Diagnostic.Switches:");
            Trace.Indent();

            foreach (var s in GetSwitches())
            {
                var bs = s as BooleanSwitch;
                var ss = s as SourceSwitch;
                var ts = s as TraceSwitch;

                if (bs != null)
                    Trace.WriteLine(String.Format("{0} : !BooleanSwitch {1}", s.DisplayName, bs.Enabled));
                else if (ss != null)
                    Trace.WriteLine(String.Format("{0} : !SourceSwitch {1}", s.DisplayName, ss.Level));
                else if (ts != null)
                    Trace.WriteLine(String.Format("{0} : !TraceSwitch {1}", s.DisplayName, ts.Level));
                else
                {
                    Trace.WriteLine(String.Format("{0} : !{1}", s.DisplayName, s.GetType().FullName));
                }
            }
            Trace.Unindent();
        }
    }
}
